home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v8n16.arc / DOSTERM.ASM < prev    next >
Assembly Source File  |  1989-08-30  |  7KB  |  274 lines

  1. ;; DOSTERM.ASM - A DOS terminal emulation program
  2. ;;
  3. ;; This code illustrates how a program written for the DOS
  4. ;; environment can program the UART and interrupt controller
  5. ;; for interrupt-driven serial I/O.  An ISR is set up to
  6. ;; service received data ready interrupts coming from IRQ4 (COM1)
  7. ;; and buffer the data in a 1,024-byte circular queue similar to
  8. ;; the BIOS keyboard buffer.
  9. ;;
  10. ;; Characters are read from the queue by calling the subroutine
  11. ;; READ_CHAR.  Characters transmitted are output directly to the
  12. ;; UART by SEND_CHAR.  Execution ends when the Esc key is pressed.
  13. ;;
  14. ;; Copyright (c) 1989 Ziff Communications Company
  15.  
  16. INTA00        equ    20h            ;8259A IRQ control register
  17. INTA01        equ    21h            ;8259A IRQ mask register
  18.  
  19. data        segment    word public 'DATA'
  20. error_msg    db    "COM1 not installed",13,10,"$"
  21. data_buffer    db    1024 dup (?)        ;input buffer
  22. buffer_start    dw    offset data_buffer    ;starting buffer address
  23. buffer_end    dw    offset buffer_start    ;ending buffer address
  24. buffer_head    dw    offset data_buffer    ;location for next write
  25. buffer_tail    dw    offset data_buffer    ;location for next read
  26. uart_addr    dw    ?            ;UART base address
  27. int0Ch        dd    ?            ;old interrupt 0Ch vector
  28. data        ends
  29.  
  30. stack        segment    stack
  31.         dw    256 dup (?)        ;stack area
  32. stack        ends
  33.  
  34. code        segment    word public 'CODE'
  35.         assume    cs:code,ds:data,ss:stack
  36.  
  37. ;;
  38. ;; MAIN initializes the system for interrupt-driven input and
  39. ;; calls TERM to perform terminal emulation functions.
  40. ;;
  41.  
  42. main        proc    far
  43.         mov    ax,data            ;point DS to the data
  44.         mov    ds,ax            ;  segment
  45. ;
  46. ;Obtain the base address of COM1 from the BIOS data area.
  47. ;
  48.         mov    ax,40h            ;point ES to data area
  49.         mov    es,ax
  50.         mov    ax,word ptr es:[0]    ;get the word at 0040:0000h
  51.         mov    uart_addr,ax        ;save it
  52.  
  53.         or    ax,ax            ;exit on error if COM1
  54.         jnz    vector            ;  is not installed
  55.         mov    ah,9
  56.         mov    dx,offset error_msg
  57.         int    21h
  58.         mov    ax,4C01h
  59.         int    21h
  60. ;
  61. ;Save the old interrupt 0Ch vector and point it to READ_COM.
  62. ;
  63. vector:        mov    ax,350Ch        ;obtain and save the current
  64.         int    21h            ;  value of the int 0Ch
  65.         mov    word ptr int0Ch,bx    ;  vector
  66.         mov    word ptr int0Ch[2],es
  67.  
  68.         assume    ds:nothing        ;save DS
  69.         push    ds
  70.         mov    ax,cs
  71.         mov    ds,ax
  72.         mov    ax,250Ch        ;revector to our own
  73.         mov    dx,offset read_com    ;  interrupt handler
  74.         int    21h
  75.         pop    ds            ;restore DS
  76.         assume    ds:data
  77. ;
  78. ;Initialize the UART to 9600 N81.
  79. ;
  80.         mov    ax,00E3h        ;9600 bps, no parity,
  81.         xor    dx,dx            ;  8 data bits, and 1
  82.         int    14h            ;  stop bit
  83. ;
  84. ;Unmask IRQ4 interrupts in the 8259's IRQ mask register.
  85. ;
  86.         in    al,INTA01        ;clear bit 4 to unmask
  87.         and    al,0EFh            ;  IRQ4 (COM1) interrupts
  88.         out    INTA01,al
  89. ;
  90. ;Initialize the Interrupt Enable Register and assert GPO2.
  91. ;
  92.         mov    dx,uart_addr        ;first clear DLAB
  93.         add    dx,3
  94.         in    al,dx
  95.         and    al,07Fh
  96.         out    dx,al
  97.  
  98.         sub    dx,2            ;set bit 0 for received data
  99.         mov    al,1            ;  ready interrupts
  100.         out    dx,al
  101.  
  102.         add    dx,3            ;assert GPO2, DTR, and RTS
  103.         mov    al,0Bh
  104.         out    dx,al
  105. ;
  106. ;Send and receive characters until ESC is pressed.
  107. ;
  108.         call    term
  109. ;
  110. ;Reset the system and exit.
  111. ;
  112.         mov    dx,uart_addr        ;clear bits 0, 1, and 3 of
  113.         add    dx,4            ;  the Modem Control Register
  114.         in    al,dx
  115.         and    al,0F4h
  116.         out    dx,al
  117.  
  118.         sub    dx,3            ;disable UART interrupts
  119.         xor    al,al
  120.         out    dx,al
  121.  
  122.         in    al,INTA01        ;mask off IRQ4 interrupts
  123.         or    al,10h            ;  that reach the 8259A
  124.         out    dx,al
  125.  
  126.         mov    ax,250Ch        ;reset the int 0Ch vector
  127.         lds    dx,[int0Ch]
  128.         int    21h
  129.  
  130.         mov    ax,4C00h        ;terminate
  131.         int    21h
  132. main        endp
  133.  
  134. ;;
  135. ;; TERM transmits characters typed at the keyboard and displays those
  136. ;; received at the serial port.
  137. ;;
  138.  
  139. term        proc    near
  140. ;
  141. ;Check the keyboard buffer and process any waiting keycodes.
  142. ;
  143. term_loop:    mov    ah,1            ;don't read the keyboard if
  144.         int    16h            ;  nothing is waiting
  145.         jz    keys_clear
  146.  
  147.         xor    ah,ah            ;read keycode
  148.         int    16h
  149.         or    al,al            ;ignore extended keycodes
  150.         jz    keys_clear
  151.         cmp    al,01Bh            ;exit if ESC was pressed
  152.         jne    output
  153.         ret
  154.  
  155. output:        push    ax            ;display the character
  156.         call    display_char
  157.         pop    ax
  158.  
  159.         call    send_char        ;output the character
  160. ;
  161. ;Check the serial input buffer and read it if a character is waiting.
  162. ;
  163. keys_clear:    mov    ax,buffer_tail        ;loop back if the buffer is
  164.         cmp    ax,buffer_head        ;  empty
  165.         je    term_loop
  166.  
  167.         call    read_char            ;extract character from buffer
  168.  
  169.         call    display_char        ;display it
  170.         jmp    term_loop        ;return to loop
  171. term        endp
  172.  
  173. ;;
  174. ;; READ_CHAR waits for a character to appear in the serial input
  175. ;; queue, then reads it and returns it in AL.
  176. ;;
  177.  
  178. read_char    proc    near
  179. no_char:    mov    bx,buffer_tail        ;loop until a character
  180.         cmp    bx,buffer_head        ;  appears in the serial
  181.         je    no_char            ;  input buffer
  182.  
  183.         cli                ;interrupts off
  184.         mov    al,[bx]            ;read a byte from the buffer
  185.         inc    bx            ;  and advance the tail
  186.         cmp    bx,buffer_end        ;wrap around to start of buffer
  187.         jne    read_exit        ;  if necessary
  188.         mov    bx,buffer_start
  189. read_exit:    mov    buffer_tail,bx
  190.  
  191.         sti                ;interrupts on
  192.         ret                ;  and exit
  193. read_char    endp
  194.  
  195. ;;
  196. ;; DISPLAY_CHAR writes the character in AL to the screen buffer.
  197. ;;
  198.  
  199. display_char    proc    near
  200.         mov    ah,0Eh            ;BIOS TTy function
  201.         xor    bh,bh
  202.         int    10h
  203.         ret
  204. display_char    endp
  205.  
  206. ;;
  207. ;; SEND_CHAR writes the character in AL to COM1.
  208. ;;
  209.  
  210. send_char    proc    near
  211.         push    ax            ;save character code
  212.         mov    dx,uart_addr        ;point DX to Line Status
  213.         add    dx,5
  214.  
  215. send_loop:    in    al,dx            ;loop until Transmit
  216.         test    al,20h            ;  Holding register
  217.         jz    send_loop        ;  is empty
  218.  
  219.         sub    dx,5            ;then output the character
  220.         pop    ax
  221.         out    dx,al
  222.         ret
  223. send_char    endp
  224.  
  225. ;;
  226. ;; READ_COM handles interrupts generated by COM1 when a byte of data
  227. ;; is received.  Data is read from the UART's Receive Buffer register
  228. ;; and stored in a FIFO queue.
  229. ;;
  230.  
  231. read_com    proc    far
  232.         push    ax            ;save registers
  233.         push    bx
  234.         push    dx
  235.         push    ds
  236.  
  237.         mov    ax,data            ;establish DS addressability
  238.         mov    ds,ax
  239.  
  240.         mov    dx,uart_addr        ;make sure DLAB is clear
  241.         add    dx,3
  242.         in    al,dx
  243.         and    al,07Fh
  244.         out    dx,al
  245.         
  246.         mov    dx,uart_addr        ;read the character
  247.         in    al,dx
  248.  
  249.         mov    bx,buffer_head        ;calculate next head position
  250.         mov    dx,bx            ;  to make sure the buffer
  251.         inc    dx            ;  isn't full
  252.         cmp    dx,buffer_end
  253.         jne    no_wrap
  254.         mov    dx,buffer_start
  255. no_wrap:    cmp    dx,buffer_tail
  256.         je    exit_int        ;exit if buffer is full
  257.  
  258.         mov    [bx],al            ;insert character in buffer
  259.         mov    buffer_head,dx        ;advance head pointer
  260.  
  261. exit_int:    mov    al,20h            ;signal EOI to the 8259
  262.         out    INTA00,al
  263.         sti                ;interrupts on
  264.  
  265.         pop    ds            ;restore registers
  266.         pop    dx
  267.         pop    bx
  268.         pop    ax
  269.         iret                ;return from interrupt
  270. read_com    endp
  271.  
  272. code        ends
  273.         end    main
  274.